package com.study.juc.threadpool;

import com.sun.jmx.remote.internal.ArrayQueue;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class SimpleThreadPool extends Thread implements ThreadPool{
    
   
    private final int  initSize;
    private final int  coreSize;
    private final int  maxSize;

    
    private int activeCount;
    
    private final LinkedRunnableQueue runnableQueue;
    
    private final ThreadFactory threadFactory;
    
    
    private volatile boolean isShutdown =false;
    private final Queue<ThreadTask> threadQueue = new ArrayDeque<>();
    
    private final long keepAliveTime;
    private final TimeUnit timeUnit;


    public SimpleThreadPool(int initSize, int coreSize, int maxSize, int queueSize) {
        this.initSize = initSize;
        this.coreSize = coreSize;
        this.maxSize = maxSize;
        this.runnableQueue = new LinkedRunnableQueue(queueSize, new DenyPolicy.RunnableDenyPolicy(), this);;
        this.threadFactory = new SimpleThreadFactory();
        this.keepAliveTime = 10;
        this.timeUnit = TimeUnit.SECONDS;
        this.init();
    }

    public SimpleThreadPool(int initSize, int coreSize, int maxSize, LinkedRunnableQueue runnableQueue, ThreadFactory threadFactory, long keepAliveTime, TimeUnit timeUnit) {
        this.initSize = initSize;
        this.coreSize = coreSize;
        this.maxSize = maxSize;
        this.runnableQueue = runnableQueue;
        this.threadFactory = threadFactory;
        this.keepAliveTime = keepAliveTime;
        this.timeUnit = timeUnit;
        this.init();
    }

    private void init(){
        start();
        for(int i =0;i<initSize;i++){
            newThread();
        }
    }

    @Override
    public void run() {
        while( !isShutdown  && !Thread.currentThread().isInterrupted()){
            try {
                timeUnit.sleep(keepAliveTime);
            } catch (InterruptedException e) {
                isShutdown = true;
                break;
            }
            synchronized (this){
                System.out.println(Thread.currentThread().getName());
                if(isShutdown)break;
                if(runnableQueue.size()>0 && activeCount < coreSize){
                    for(int i=initSize ;i<coreSize;i++){
                        newThread();  
                    }
                    continue;
                }
                
                if(runnableQueue.size() >0 && activeCount <maxSize){
                    for(int i=coreSize ;i<maxSize;i++){
                        newThread();
                    }     
                }
                if(runnableQueue.size() == 0 && activeCount >coreSize){
                    for(int i=coreSize ;i<activeCount;i++){
                        removeThread();
                    }
                }
            }
        }
    }
    
    private void newThread(){
        InternalTask internalTask = new InternalTask(this.runnableQueue);
        Thread thread = threadFactory.createTread(internalTask);
        threadQueue.offer(new ThreadTask(thread,internalTask));
        this.activeCount++;
        thread.start();
    }
    private void removeThread(){
        ThreadTask remove = threadQueue.remove();
        remove.task.stop();
        this.activeCount--;
    }

    @Override
    public void execute(Runnable runnable) {
        if(!isShutdown){
            this.runnableQueue.offer(runnable);
        }else{
            throw new IllegalArgumentException("线程池已关闭");
        }
    }

    @Override
    public int getInitSize() {
        return initSize;
    }

    @Override
    public int getCoreSize() {
        return coreSize;
    }

    @Override
    public int getMaxSize() {
        return maxSize;
    }

    @Override
    public int getQueueSize() {
        return 0;
    }

    @Override
    public int getActiveCount() {
       synchronized (this){
           return activeCount;
       }
    }

    @Override
    public void shutDown() {
        synchronized (this){
            if(isShutdown) return;
            isShutdown =true;
            threadQueue.forEach(threadTask -> {
                threadTask.task.stop();
                threadTask.thread.interrupt();
            });
            this.interrupt();
        }
    }

    @Override
    public boolean isShutDown() {
        return isShutdown;
    }

    
    private static class ThreadTask {
        Thread thread;
        InternalTask task;

        public ThreadTask() {
        }

        public ThreadTask(Thread thread, InternalTask task) {
            this.thread = thread;
            this.task = task;
        }
    }
    
    private static class  SimpleThreadFactory implements ThreadFactory{

        private AtomicInteger count = new AtomicInteger(0);
        @Override
        public Thread createTread(Runnable runnable) {
            return new Thread(runnable,"mytheadpool thread:"+count.incrementAndGet());
        }
    }
}
